﻿using System;
using System.Reflection;
using fastCSharp.reflection;
using System.Reflection.Emit;
using System.Collections.Generic;
using fastCSharp.threading;
using System.Runtime.CompilerServices;

namespace fastCSharp.emit
{
    /// <summary>
    /// 默认构造函数
    /// </summary>
    public sealed class constructor : Attribute
    {
    }
    /// <summary>
    /// 默认构造函数
    /// </summary>
    /// <typeparam name="valueType">数据类型</typeparam>
    public static class constructor<valueType>
    {
        /// <summary>
        /// 默认构造函数
        /// </summary>
        public static readonly Func<valueType> New;
        /// <summary>
        /// 默认空值
        /// </summary>
        /// <returns>默认空值</returns>
        [MethodImpl((MethodImplOptions)fastCSharp.pub.MethodImplOptionsAggressiveInlining)]
        public static valueType Default()
        {
            return default(valueType);
        }

        static constructor()
        {
            Type type = typeof(valueType);
            if (type.IsValueType || type.IsArray || type == typeof(string))
            {
                New = Default;
                return;
            }
            if (fastCSharp.code.typeAttribute.GetAttribute<constructor>(type, false, true) != null)
            {
                foreach (fastCSharp.code.attributeMethod methodInfo in fastCSharp.code.attributeMethod.GetStatic(type))
                {
                    if (methodInfo.Method.ReflectedType == type && methodInfo.Method.GetParameters().Length == 0 && methodInfo.GetAttribute<constructor>(true) != null)
                    {
                        New = (Func<valueType>)Delegate.CreateDelegate(typeof(Func<valueType>), methodInfo.Method);
                        return;
                    }
                }
            }
            if (!type.IsInterface && !type.IsAbstract)
            {
                ConstructorInfo constructorInfo = type.GetConstructor(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, nullValue<Type>.Array, null);
                if (constructorInfo != null)
                {
                    DynamicMethod dynamicMethod = new DynamicMethod("constructor", type, nullValue<Type>.Array, type, true);
                    dynamicMethod.InitLocals = true;
                    ILGenerator generator = dynamicMethod.GetILGenerator();
                    generator.Emit(OpCodes.Newobj, constructorInfo);
                    generator.Emit(OpCodes.Ret);
                    New = (Func<valueType>)dynamicMethod.CreateDelegate(typeof(Func<valueType>));
                }
            }
        }
    }
}
